package com.yhuk.oauth.server.web;

import com.netflix.ribbon.proxy.annotation.Http;
import com.yhuk.oauth.server.model.User;
import com.yhuk.oauth.server.service.UserService;
import com.yhuk.oauth.server.utils.JsonUtils;
import com.yhuk.oauth.server.utils.RedisUtil;
import com.yhuk.oauth.server.utils.ResponseUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author xiaolang
 * @version 1.0.0
 */
@RestController
@CrossOrigin
public class LoginController {
    private static Logger logger = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private ClientDetailsService clientDetailsService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserService userService;
    @RequestMapping("login")
    public String login(HttpServletRequest request,HttpServletResponse response, HttpSession session, User user, @RequestParam("client_id")String clientId) throws IOException {
        logger.info("登录客户端Id:{},登录名称:{}",clientId,user.getUserName());

        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
        String callbackUrl = getCallbackUrl(clientDetails.getRegisteredRedirectUri());
        if(callbackUrl == null){
            return  ResponseUtils.getErrorJson("1002","回调路径未设置");
        }
        if(Boolean.TRUE.equals(session.getAttribute("isLogin"))){
            logger.info("已经建立了全局会话,token:{},session_id:{}",session.getAttribute("token"),session.getId());
            redisUtil.set(session.getAttribute("token").toString(),
                    JsonUtils.toJson(userService.loadByLoginName(user.getUserName())),60*60*5); //五个小时
            logger.info("token过期时间:{}",redisUtil.getExpire(session.getAttribute("token").toString()));
            response.sendRedirect(callbackUrl+"?token="+session.getAttribute("token").toString());
            return ResponseUtils.getErrorJson("1002","跳转失败");
        }

        logger.info("clientId:{},ClientDetails:{}",clientId,JsonUtils.toJson(clientDetails));
        //此方法要重新刷新授权
        OAuth2AccessToken oAuth2AccessToken = TokenUtils.getToken(user,clientDetails);
        if(oAuth2AccessToken.getValue() == null){
            return ResponseUtils.getErrorJson("1001","授权失败");
        }
        //建立全局会话
        session.setAttribute("isLogin",true);
        session.setAttribute("token",oAuth2AccessToken.getValue());
        //保存用户信息到redis
        redisUtil.set(oAuth2AccessToken.getValue(),JsonUtils.toJson(userService.loadByLoginName(user.getUserName())),300);
        //去建立局部会话
        response.sendRedirect(callbackUrl+"?token="+oAuth2AccessToken.getValue());
        return ResponseUtils.getErrorJson("1003","跳转失败");
    }
    @RequestMapping("is_login")
    public String test(HttpServletRequest request,HttpSession session,HttpServletResponse response,String token){
        logger.info("------cookies:{}--------",JsonUtils.toJson(request.getCookies()));
        if(Boolean.TRUE.equals(session.getAttribute("isLogin"))){
            logger.info("token:{}",session.getAttribute("token"));
        }
        return  session.getAttribute("token").toString();
    }

    @RequestMapping("sessionTest")
    public String testSession(HttpServletRequest request){
        return request.getSession().getAttribute("token").toString();

    }

    public String getCallbackUrl(Set<String> redirectSet){
        if(redirectSet==null){
            return null;
        }
        String[] redirectUrls = redirectSet.toArray(new String[0]);
        if(redirectUrls==null || redirectUrls.length<=0){
            return null;
        }
       return redirectUrls[0];
    }

    private static class TokenUtils{
        public static OAuth2AccessToken getToken(User user,ClientDetails clientDetails) throws IOException {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost("http://localhost:8888/authorize/oauth/token");
            httpPost.setHeader("Authorization",getAuthorizationHeader(clientDetails));
            List<BasicNameValuePair> params = new ArrayList<>();
            params.add(new BasicNameValuePair("grant_type","password"));
            params.add(new BasicNameValuePair("username",user.getUserName()));
            params.add(new BasicNameValuePair("password",user.getPassword()));
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params,"UTF-8");
            httpPost.setEntity(formEntity);
            CloseableHttpResponse response = httpClient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            //读取内容
            String content = EntityUtils.toString(httpEntity, "UTF-8");
            logger.info("授权返回内容:{}",content);
            OAuth2AccessToken oAuth2AccessToken = JsonUtils.toObject(content,OAuth2AccessToken.class);
            return oAuth2AccessToken;
        }
        public static String getAuthorizationHeader(ClientDetails clientDetails){
            String auth = clientDetails.getClientId()+":"+clientDetails.getClientSecret();
            byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
            String authHeader = "Basic " + new String(encodedAuth);
            return authHeader;
        }
    }
}
